package cn.com.bluemoon.daps.model.service.impl;

import cn.com.bluemoon.daps.common.domain.BaseModel;
import cn.com.bluemoon.daps.common.domain.ResultBean;
import cn.com.bluemoon.daps.common.enums.BmStatus;
import cn.com.bluemoon.daps.common.enums.DatabaseType;
import cn.com.bluemoon.daps.common.exception.DapException;
import cn.com.bluemoon.daps.common.toolkit.valueobject.MyQueryCallable;
import cn.com.bluemoon.daps.model.dto.FieldStandardDto;
import cn.com.bluemoon.daps.model.dto.ModelTableInfoDto;
import cn.com.bluemoon.daps.model.entity.DapDataModelRelatedStandardResult;
import cn.com.bluemoon.daps.model.entity.DapDataModelTable;
import cn.com.bluemoon.daps.model.entity.DapDataModelTableField;
import cn.com.bluemoon.daps.model.entity.DapDataModelTablePartition;
import cn.com.bluemoon.daps.model.mapper.DapDataModelTableFieldMapper;
import cn.com.bluemoon.daps.model.mapper.DapDataModelTablePartitionMapper;
import cn.com.bluemoon.daps.model.service.DapDataModelFieldRenameRecordService;
import cn.com.bluemoon.daps.model.service.DapDataModelRelatedStandardResultService;
import cn.com.bluemoon.daps.model.service.DapDataModelTableFieldService;
import cn.com.bluemoon.daps.model.service.DapDataModelTableService;
import cn.com.bluemoon.daps.model.vo.InsertModelTableFieldVo;
import cn.com.bluemoon.daps.model.vo.RelationIds;
import cn.com.bluemoon.daps.model.vo.RelationIdsVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

/**
 * <p>
 * 数据模型-模型中设计表-字段的表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2020-08-03
 */
@Slf4j
@Service
public class DapDataModelTableFieldServiceImpl extends ServiceImpl<DapDataModelTableFieldMapper, DapDataModelTableField>
        implements DapDataModelTableFieldService {

    @Resource
    DapDataModelTableFieldMapper dapDataModelTableFieldMapper;

    @Resource
    DapDataModelTableService dapDataModelTableService;

    @Resource
    DapDataModelRelatedStandardResultService dapDataModelRelatedStandardResultService;

    @Resource
    DapDataModelTablePartitionMapper dapDataModelTablePartitionMapper;

    @Resource
    DapDataModelFieldRenameRecordService dapDataModelFieldRenameRecordService;

    /**
     * 通过模型表id获得字段列表
     *
     * @param id
     * @return
     */
    @Override
    public List<FieldStandardDto> getFieldList(String id) {

        // 查询字段
        List<DapDataModelTableField> fields = dapDataModelTableFieldMapper.selectList(new LambdaQueryWrapper<DapDataModelTableField>()
                .eq(DapDataModelTableField::getModelTableId, id)
                .eq(DapDataModelTableField::getBmStatus, BmStatus.ON.getCode()).orderByAsc(DapDataModelTableField::getFieldRank));
        List<FieldStandardDto> fieldStandardDtos = dapDataModelTableFieldMapper.selectFieldInfo(id, BmStatus.ON.getCode());
        if(fields.size() != fieldStandardDtos.size()){
            List<String> fieldIds = fieldStandardDtos.stream().map(FieldStandardDto::getField).map(DapDataModelTableField::getId).collect(Collectors.toList());
            List<DapDataModelTableField> collect = fields.stream().filter(f -> !fieldIds.contains(f.getId())).collect(Collectors.toList());
            List<FieldStandardDto> dtos = Lists.newArrayList();
            for (DapDataModelTableField field : collect){
                for(FieldStandardDto dto : fieldStandardDtos){
                    if(dto.getField().getStandardId().equals(field.getStandardId())){
                        FieldStandardDto fieldStandardDto = new FieldStandardDto();
                        fieldStandardDto.setEngName(dto.getEngName());
                        fieldStandardDto.setSId(dto.getSId());
                        fieldStandardDto.setName(dto.getName());
                        fieldStandardDto.setField(field);
                        dtos.add(fieldStandardDto);
                    }
                }
            }
            if(!dtos.isEmpty()){
                fieldStandardDtos.addAll(dtos);
            }
            // 重新排序
            List<FieldStandardDto> collects = fieldStandardDtos.stream().sorted(Comparator.comparing(x -> x.getField().getFieldRank())).collect(Collectors.toList());
            return collects;
        }
        return fieldStandardDtos;
    }

    /**
     * 获得表及字段信息
     *
     * @param modelTableId
     * @return
     */
    @Override
    public ModelTableInfoDto getTableInfo(String modelTableId) {

        ModelTableInfoDto dto = dapDataModelTableFieldMapper.selectTableInfo(modelTableId, BmStatus.ON.getCode());
        if(dto != null){
            dto.setFieldList(dto.getFieldList().isEmpty() ? dto.getFieldList() : dto.getFieldList().stream()
                    .filter(t -> t.getBmStatus().equals(BmStatus.ON)).collect(Collectors.toList()));
        }
        return dto;
    }

    /**
     * 删除备份的字段
     *
     * @param modelId
     */
    @Override
    public void deleteField(String modelId) {

        dapDataModelTableFieldMapper.deleteField(modelId);
    }

    /**
     * 未关联标准引用
     *
     * @param result
     */
    @Override
    @Transactional(rollbackFor = {DapException.class, Exception.class})
    public Boolean useStandard(RelationIdsVo result) {

        boolean update = true;
        for (RelationIds ids : result.getRelationIds()) {
            // 表示类型为忽略
            if ("1".equals(result.getIsIgnore())) {
                // 删除掉忽略记录
                dapDataModelRelatedStandardResultService.getBaseMapper()
                        .delete(new QueryWrapper<DapDataModelRelatedStandardResult>().eq("model_table_field_id", ids.getPId()));

            }
            update = this.update(new UpdateWrapper<DapDataModelTableField>()
                    .set("standard_method", ids.getStandardMethod())
                    .set("standard_id", ids.getSId())
                    .eq("id", ids.getPId()).or().eq("p_id", ids.getPId()));

        }
        return update;
    }

    /**
     * 批量新增字段
     */
    @Override
    @Transactional(rollbackFor = {DapException.class, RuntimeException.class})
    public ResultBean<Boolean> insertField(InsertModelTableFieldVo fields, DatabaseType databaseType) {

        // 表id
        String id = fields.getFields().stream().map(DapDataModelTableField::getModelTableId).findFirst().get();
        DapDataModelTable table = dapDataModelTableService.getBaseMapper().selectById(id);
        if(table == null){
            return ResultBean.error("字段所在的表不存在，请重新刷新页面");
        }
        // 检查提交的字段是否有删除的字段
        List<String> ids = fields.getFields().stream().filter(f -> StringUtils.isNotBlank(f.getId()))
                .map(DapDataModelTableField::getId).collect(Collectors.toList());
        // 校验是否有删除的数据
        if(!ids.isEmpty()){
            List<DapDataModelTableField> field = dapDataModelTableFieldMapper.selectBatchIds(ids);
            boolean flag = field.stream().noneMatch(f -> f.getBmStatus() == BmStatus.DELETE);
            if(!flag){
                return ResultBean.error("字段列表存在已删除的数据，请刷新页面");
            }
        }
        // 检查新增的数据是否和数据库重复
        List<String> fieldNames = fields.getFields().stream().filter(f -> StringUtils.isBlank(f.getId()))
                .map(DapDataModelTableField::getFieldName).collect(Collectors.toList());
        // 查询库中的数据
        if(!fieldNames.isEmpty()){
            List<DapDataModelTableField> fieldList = dapDataModelTableFieldMapper
                    .selectList(new LambdaQueryWrapper<DapDataModelTableField>()
                            .eq(DapDataModelTableField::getModelTableId, id)
                            .in(DapDataModelTableField::getFieldName, fieldNames)
                            .eq(DapDataModelTableField::getBmStatus, BmStatus.ON.getCode()));
            // 验证字段是否重复
            if(!fieldList.isEmpty()){
                List<String> names = fieldList.stream().map(DapDataModelTableField::getFieldName).collect(Collectors.toList());
                return ResultBean.error("数据库已存在:"+names.toString()+"字段，请重新命名");
            }
            // 查询分区是否和字段重复
            List<DapDataModelTablePartition> partitionList = dapDataModelTablePartitionMapper.selectList(new LambdaQueryWrapper<DapDataModelTablePartition>()
                    .eq(DapDataModelTablePartition::getModelTableId, id)
                    .eq(DapDataModelTablePartition::getBmStatus, BmStatus.ON.getCode())
                    .in(DapDataModelTablePartition::getPartitionFieldName, fieldNames));
            if(!partitionList.isEmpty()){
                return ResultBean.error("字段名和分区名重复");
            }
            // 筛选出新增的字段名
            List<DapDataModelTableField> addField = fields.getFields().stream().filter(f -> StringUtils.isBlank(f.getId())).collect(Collectors.toList());
            if(!addField.isEmpty()){
                fields.getFields().removeAll(addField);
                for(DapDataModelTableField field : addField){
                    field.setId(getRenewField(field.getModelTableId(), field.getFieldName()));
                };
                fields.getFields().addAll(addField);
            }
        }
        List<DapDataModelTableField> collect = fields.getFields().stream()
                .peek(t -> t.setUpdateTime(null)).collect(Collectors.toList());
        // 检查是否有重命名的字段
        dapDataModelFieldRenameRecordService.fieldIsRename(fields.getFields());
        // 批量新增或插入
        log.info(String.format("表%s(%s)更新数据", table.getEngName(),table.getId()));
        Boolean flag = this.saveOrUpdateBatch(collect);

        // 建表语句SQL关键字检查
        String dataModelId = table.getDataModelId();
        String tableId = table.getId();
        dapDataModelTableService.checkTableCreateSql(databaseType, dataModelId, tableId);
        // 刷新表更新时间
        dapDataModelTableService.saveTime(fields.getFields().stream().findFirst().get().getModelTableId());
        return ResultBean.ok(flag);
    }

    /**
     * 分页方式获取对应条件的所有数据
     * 1根据查询条件获取字段数量(condition+query)
     * 2制定分片大小规则
     * 3开启多分片多线程的方式进行查询
     * 4合并数据并返回
     *
     * @param modelId 模id
     * @param newest  true 最新 f 历史
     * @return 所有
     */
    @Override
    public List<DapDataModelTableField> findAllByPageByModelIdAndNewest(String modelId, boolean newest) {
        //一次查询多少条
        int limit = 1000;
        return multiDBQuery(new MyQueryCallable<DapDataModelTableField>() {

            /**
             * 获取查询的总数
             *
             * @return 总数
             */
            @Override
            public int count() {
                LambdaQueryWrapper<DapDataModelTableField> eq = bmLambdaQuery().eq(DapDataModelTableField::getDataModelId, modelId)
                        .eq(DapDataModelTableField::getDataNewest, (newest ? 1 : 0))
                        .eq(newest, DapDataModelTableField::getPId, "0");
                return getBaseMapper().selectCount(eq);
            }

            /**
             * 定义一个任务的查询逻辑
             *
             * @param offset 查询db的offset
             * @param limit  查询db的总数
             * @return 一个任务
             */
            @Override
            public Callable<List<DapDataModelTableField>> callTask(int offset, int limit) {
                return () -> getBaseMapper().findAllByModelIdAndNewestLimit(modelId, newest, offset, limit);
            }
        }, limit);
    }

    /**
     * 删除字段后进行排序
     * @param tableId
     */
    @Override
    public void fieldRank(String tableId) {

        // 查询最新字段数据
        List<DapDataModelTableField> fields = this.getBaseMapper().selectList(new LambdaQueryWrapper<DapDataModelTableField>()
                .eq(DapDataModelTableField::getModelTableId, tableId)
                .eq(DapDataModelTableField::getBmStatus, BmStatus.ON.getCode())
                .orderByAsc(DapDataModelTableField::getFieldRank));
        if(!fields.isEmpty()){
            for (int i = 1; i <= fields.size(); i++) {
                fields.get(i-1).setFieldRank(i);
            }
            this.updateBatchById(fields);
        }
    }

    @Override
    public String getRenewField(String tableId, String fieldName) {

        // 查询对应的版本表
        List<DapDataModelTable> tables = dapDataModelTableService.getBaseMapper().selectList(new LambdaQueryWrapper<DapDataModelTable>()
                .eq(DapDataModelTable::getPId, tableId).eq(BaseModel::getBmStatus, BmStatus.ON.getCode()));
        if(!tables.isEmpty()){
            DapDataModelTable table = tables.stream().findFirst().get();
            // 查询版本数据
            List<DapDataModelTableField> fields = this.getBaseMapper().selectList(new LambdaQueryWrapper<DapDataModelTableField>()
                    .eq(DapDataModelTableField::getModelTableId, table.getId()).eq(DapDataModelTableField::getFieldName, fieldName)
                    .eq(DapDataModelTableField::getBmStatus, BmStatus.ON.getCode()).ne(DapDataModelTableField::getPId, "0"));
            if(!fields.isEmpty()){
                DapDataModelTableField field = fields.stream().findFirst().get();
                return field.getPId();
            }
        }
        return null;
    }

}
